package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.FormDataValidateDataHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.SerialNoHelp;
import com.xbongbong.paas.help.team.TeamUserHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.AddMuchFieldPojo;
import com.xbongbong.paas.pojo.dto.AddBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PaymentErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.sheet.pojo.SheetAttrPojo;
import com.xbongbong.pro.sheet.pojo.dto.SheetAmountDetailGetDTO;
import com.xbongbong.pro.sheet.pojo.vo.SheetAmountDetailGetVO;
import com.xbongbong.pro.team.TeamAfterVerifyDTO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.OnlinePaymentFlowEntity;
import com.xbongbong.saas.domain.entity.PaymentBalanceEntity;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.LinkAddOperationFlagEnum;
import com.xbongbong.saas.enums.OnlinePaymentFlowDistributorEnum;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.PaymentSheetDistributorEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaasPaymentHelper;
import com.xbongbong.saas.help.SaasPaymentSheetHelper;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.help.workflow.ContractHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.PaymentBalanceModel;
import com.xbongbong.saas.service.toolbox.help.SaasSaveHelper;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;

/**
 * @author 吴峰
 * @date 2021/07/15 14:28
 */
@Service("paymentSheetAnalyticalServiceImpl")
public class PaymentSheetValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PaymentSheetValidateAnalyticalServiceImpl.class);

    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private FormDataValidateDataHelp formDataValidateDataHelp;
    @Resource
    private PaymentBalanceModel paymentBalanceModel;
    @Resource
    private SerialNoHelp serialNoHelp;
    @Resource
    private SaasSaveHelper saasSaveHelper;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private SaasPaymentHelper saasPaymentHelper;
    @Resource
    private ContractHelp contractHelp;
    @Resource
    private SaasPaymentSheetHelper saasPaymentSheetHelper;
    @Resource
    private AnalyticalHelp analyticalHelp;
    @Resource
    private TeamUserHelp teamUserHelp;

    private static final String OPERATE = "operate";

    /**
     * 引用不到WorkflowOperateEnum，所以只能这边写死一个值，已枚举里面维护的为准
     */
    private static final String OPERATE_ADD_VALUE = "1";


    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), XbbRefTypeEnum.BAD_DEBT.getCode(), XbbRefTypeEnum.WRITE_OFF_PREPAYMENT.getCode(),
                XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode(), XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode(), XbbRefTypeEnum.RED_PREPAYMENT.getCode(), XbbRefTypeEnum.PREPAYMENT.getCode(), XbbRefTypeEnum.PREPAYMENT_BALANCE.getCode(), XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
    }
    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
    }

    /**
     *
     * 这边会有点特殊逻辑，目前新增进审批之后，在节点之间流转也会有dataId。编辑进审批之后，节点之间流转也会有dataId。但是我要区分新增进审批和编辑进审批
     * 为什么要区分新增进审批和编辑进审批？因为结合之前工作流上线之前的现状，编辑以及编辑进审批不需要进行校验只需要参数封装。所以这边先临时解决，通过中间流转表去处理。
     * 后续如果做了资金前置的化，这部分逻辑可以去掉。
     *
     * @param validateDataDTO
     * @throws XbbException
     */
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException{
       try {
           boolean isNew = analyticalHelp.isNew(validateDataDTO.getDataId(), validateDataDTO.getTaskId(), validateDataDTO.getCorpid());
           JSONArray amountDetail = validateDataDTO.getAmountDetail();
           //因工作流需求，现在把校验逻辑从save里面迁移到beforeSave里面
           JSONObject data = validateDataDTO.getData();
           SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CUSTOMER_ID.getAttr(), PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), PaymentSheetEnum.CUSTOMER_ID.getFieldType());
           SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CONTRACT.getAttr(), PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentSheetEnum.CONTRACT.getFieldType());
           SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.PAYMENT.getAttr(), PaymentSheetEnum.PAYMENT_LINK_TEXT.getAttr(), PaymentSheetEnum.PAYMENT.getFieldType());
           SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.RED_SHEET.getAttr(), PaymentSheetEnum.RED_SHEET_LINK_TEXT.getAttr(), PaymentSheetEnum.RED_SHEET.getFieldType());
           Integer businessType = validateDataDTO.getBusinessType();
           String type = FastJsonHelper.getStringFromFormData(data, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
           PaymentSheetTypeEnum paymentSheetTypeEnum = null;
           //处理回款单明细中子回款单的标签
           if(CollectionsUtil.isNotEmpty(amountDetail)){
               saasSaveHelper.dealLabelDataForSheet(amountDetail,validateDataDTO);
           }
           if (StringUtil.isNotEmpty(type)) {
               paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(type);
               data.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), paymentSheetTypeEnum.getCode());
           } else {
               paymentSheetTypeEnum = PaymentSheetTypeEnum.getByBusinessType(businessType);
               data.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), paymentSheetTypeEnum.getCode());
           }
           SheetTypeEnum sheetTypeEnum = paymentSheetTypeEnum.getSheetTypeEnum();
           //校验明细金额，退货id处理等
           saasSaveHelper.sheetBeforeSave(validateDataDTO, data, sheetTypeEnum);
           validateDataDTO.setBusinessType(sheetTypeEnum.getBusinessType());
           //处理经销商支付方式
           SaveFormatHelp.handlePayMethod4Distributor(validateDataDTO.getPlatform(), data, paymentSheetTypeEnum.getCode(), validateDataDTO.getDistributorMark());
           //封装回款单的支付流水
           OnlinePaymentFlowEntity onlinePaymentFlowEntity = validateDataDTO.getOnlinePaymentFlowEntity();
           if (Objects.nonNull(onlinePaymentFlowEntity)) {
               JSONObject onlineJson = onlinePaymentFlowEntity.getData();
               Long id = onlinePaymentFlowEntity.getId();
               String serialNo = onlinePaymentFlowEntity.getSerialNo();
               Long payerId = onlineJson.getLong(OnlinePaymentFlowDistributorEnum.PAYER_ID.getAttr());
               String payerText = onlineJson.getString(OnlinePaymentFlowDistributorEnum.PAYER_ID_LINK_TEXT.getAttr());
               data.put(PaymentSheetDistributorEnum.ONLINE_PAYMENT_FLOW.getAttr(), id);
               data.put(PaymentSheetDistributorEnum.ONLINE_PAYMENT_FLOW_LINK_TEXT.getAttr(), serialNo);
               data.put(PaymentSheetDistributorEnum.PAYER_ID.getAttr(), payerId);
               data.put(PaymentSheetDistributorEnum.PAYER.getAttr(), payerText);
           }
           if (!Objects.equals(isNew, false)) {
               if (Objects.equals(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //已核销
                   writeOffBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //预收款核销
                   writeOffBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.PREPAYMENT.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //预收款
                   prepaymentBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.RED_PREPAYMENT.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //红冲预收款
                   prepaymentBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //红冲已核销
                   redBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //红冲预收款核销
                   redBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //红冲预收款核销(退到余额)
                   redBeforeSave(validateDataDTO, sheetTypeEnum);
               } else if (Objects.equals(XbbRefTypeEnum.BAD_DEBT.getCode(), paymentSheetTypeEnum.getBusinessType())) {
                   //坏账
                   badBeforeSave(validateDataDTO, sheetTypeEnum);
               }
           }
           if (CollectionsUtil.isNotEmpty(amountDetail)) {
               SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = validateDataDTO.getSaasNeedRedundantAttrPoJo() == null ? new SaasNeedRedundantAttrPojo() : validateDataDTO.getSaasNeedRedundantAttrPoJo();
               saasNeedRedundantAttrPojo.setAmountDetail(amountDetail);
               validateDataDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
           }
       } catch (XbbException e) {
           throw e;
       } catch (Exception e) {
           LOGGER.error("paymentSheetAnalyticalServiceImpl.beforeSave error", e);
           throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
       }
    }

    /**
     * 坏账回款单
     *
     * @param validateDataDTO
     * @param sheetTypeEnum
     */
    private void badBeforeSave(ValidateDataDTO validateDataDTO, SheetTypeEnum sheetTypeEnum) throws XbbException {
        /*
         坏账：回款金额，核销金额一致
         */
        JSONObject dataList = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        String userId = validateDataDTO.getUserId();
        if (Objects.nonNull(validateDataDTO.getProcessCreatorId())) {
            userId = validateDataDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = validateDataDTO.getAmountDetail();
        //TODO 金额校验，后续修改成根据每条明细判断，暂时未用到
        double allAmount = 0D;
        //应收款和合同对应的回款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //回款单的实际坏账金额
        Double sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.AMOUNT.getAttr(), 0D);
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(XbbRefTypeEnum.PAYMENT_SHEET);
        /*
          经销商类型回款单，需要做如下事情：
          （1）（经销商端判断，此处不判断）上传凭证：线下支付则必填
          （2）支付方式，厂商端操作需后端自动赋值 - handleAmountDetail方法内处理
                代客操作：已核销，预收款
                预收款账户：预收款核销，红冲预收款核销（退到余额）
                线下打款：红冲预收款核销（原Pro的），红冲预收款余额
                另外，红冲已核销与原单一致（关联新建时处理好）
          （3）上游订货单（合同）付款状态更新
         */
        Integer distributorMark = validateDataDTO.getDistributorMark();
        validateDataDTO.setDistributorMark(distributorMark);
        //处理金额明细
        saasSaveHelper.checkAmountDetail(validateDataDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Double sumAmount = getSumAmount(validateDataDTO, contractIds, paymentIds, null);
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.BAD_AMOUNT, StringUtil.formatDouble(sumAmount));
        }
        //判断已收金额是否已经超过应收款内的未收金额
        saasPaymentHelper.checkPayment(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //判断已收金额是否已经超过合同内的未收金额
        PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(sheetTypeEnum.getCode());
        contractHelp.checkContract(distributorMark, paymentSheetTypeEnum, corpid, contractIdToAmount, contractIds);
        PaymentSheetEntityExt paymentSheetEntityExt = new PaymentSheetEntityExt();
        BeanUtil.copyProperties(validateDataDTO, paymentSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, paymentSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
    }

    /**
     * 红冲已核销、红冲预收款核销、红冲预收款核销(退到余额)
     *
     * @param validateDataDTO
     * @param sheetTypeEnum
     */
    private void redBeforeSave(ValidateDataDTO validateDataDTO, SheetTypeEnum sheetTypeEnum) throws XbbException {
        JSONObject dataList = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        String userId = validateDataDTO.getUserId();
        if (Objects.nonNull(validateDataDTO.getProcessCreatorId())) {
            userId = validateDataDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = validateDataDTO.getAmountDetail();
        //TODO 金额校验，后续修改成根据每条明细判断，暂时未用到
        double allAmount = 0D;
        //应收款和合同对应的回款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //回款单的实收回款金额
        Double sheetAmount;
        boolean redWriteOffBalanceFlag = SheetTypeEnum.onlyWriteOffAmount(sheetTypeEnum.getCode());
        if (redWriteOffBalanceFlag) {
            //红冲预收款核销(退到余额)，是用的核销金额
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D);
        } else {
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.AMOUNT.getAttr(), 0D);
        }
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(XbbRefTypeEnum.PAYMENT_SHEET);
        /*
          经销商类型回款单，需要做如下事情：
          （1）（经销商端判断，此处不判断）上传凭证：线下支付则必填
          （2）支付方式，厂商端操作需后端自动赋值 - handleAmountDetail方法内处理
                代客操作：已核销，预收款
                预收款账户：预收款核销，红冲预收款核销（退到余额）
                线下打款：红冲预收款核销（原Pro的），红冲预收款余额
                另外，红冲已核销与原单一致（关联新建时处理好）
          （3）上游订货单（合同）付款状态更新
         */
        Integer distributorMark = validateDataDTO.getDistributorMark();
        validateDataDTO.setDistributorMark(distributorMark);
        //处理金额明细
        saasSaveHelper.checkAmountDetail(validateDataDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Long linkPreId = FastJsonHelper.getLongFromFormData(dataList, PaymentSheetEnum.RED_SHEET.getAttr());
        Double sumAmount = getSumAmount(validateDataDTO, contractIds, paymentIds, linkPreId);
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_AMOUNT_RED, PaymentSheetEnum.RED_SHEET.getAttrName());
        }
        //判断已收金额是否已经超过应收款内的未收金额
        saasPaymentHelper.checkPayment(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //判断已收金额是否已经超过合同内的未收金额
        PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(sheetTypeEnum.getCode());
        contractHelp.checkContract(distributorMark, paymentSheetTypeEnum, corpid, contractIdToAmount, contractIds);
        PaymentSheetEntityExt paymentSheetEntityExt = new PaymentSheetEntityExt();
        BeanUtil.copyProperties(validateDataDTO, paymentSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, paymentSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
    }

    /**
     * 预收款、红冲预收款类型的回款单保存之前的校验以及参数封装
     *
     * @param validateDataDTO
     * @param paymentSheetTypeEnum
     */
    private void prepaymentBeforeSave(ValidateDataDTO validateDataDTO, SheetTypeEnum paymentSheetTypeEnum) throws XbbException {
        JSONObject dataList = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        if (Objects.equals(paymentSheetTypeEnum, SheetTypeEnum.RED_PREPAYMENT)) {
            Double amount = dataList.getDouble(PaymentSheetEnum.AMOUNT.getAttr());
            //检查红冲预收款余额的红冲金额是否小于客户余额
            saasPaymentSheetHelper.checkCustomerBalance(dataList, corpid, amount);
        }
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
    }

    /**
     * 保存子回款单时，跳过检验条件
     *
     * @param validateDataDTO
     * @throws XbbException
     */
    public void beforeSaveSkipValidate(ValidateDataDTO validateDataDTO) throws XbbException{
        try {
            JSONObject data = validateDataDTO.getData();
            Integer businessType = validateDataDTO.getBusinessType();
            //校验回款单金额不能为0
            SheetTypeEnum paymentSheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
            SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CUSTOMER_ID.getAttr(), PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), PaymentSheetEnum.CUSTOMER_ID.getFieldType());
            SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CONTRACT.getAttr(), PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentSheetEnum.CONTRACT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.PAYMENT.getAttr(), PaymentSheetEnum.PAYMENT_LINK_TEXT.getAttr(), PaymentSheetEnum.PAYMENT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.RED_SHEET.getAttr(), PaymentSheetEnum.RED_SHEET_LINK_TEXT.getAttr(), PaymentSheetEnum.RED_SHEET.getFieldType());

            //把回款单类型置入data内，以让进入审批的data内有回款单类型的值（注：审批内7种类型回款单都是统一为702，其类型已经在data内，所以置入类型时需要判断data内是否已经存在类型）
            String type = FastJsonHelper.getStringFromFormData(data, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
            if (StringUtil.isEmpty(type)){
                data.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), paymentSheetTypeEnum.getCode());
            } else {
                paymentSheetTypeEnum = SheetTypeEnum.getByCodeRefType(type, businessType);
            }
            //退货id处理等
            saasSaveHelper.sheetBeforeSave(validateDataDTO, data, paymentSheetTypeEnum);
            //处理经销商支付方式
            SaveFormatHelp.handlePayMethod4Distributor(validateDataDTO.getPlatform(), data, paymentSheetTypeEnum.getCode(), validateDataDTO.getDistributorMark());
            //封装回款单的支付流水
            OnlinePaymentFlowEntity onlinePaymentFlowEntity = validateDataDTO.getOnlinePaymentFlowEntity();
            if (Objects.nonNull(onlinePaymentFlowEntity)) {
                JSONObject onlineJson = onlinePaymentFlowEntity.getData();
                Long id = onlinePaymentFlowEntity.getId();
                String serialNo = onlinePaymentFlowEntity.getSerialNo();
                Long payerId = onlineJson.getLong(OnlinePaymentFlowDistributorEnum.PAYER_ID.getAttr());
                String payerText = onlineJson.getString(OnlinePaymentFlowDistributorEnum.PAYER_ID_LINK_TEXT.getAttr());
                data.put(PaymentSheetDistributorEnum.ONLINE_PAYMENT_FLOW.getAttr(), id);
                data.put(PaymentSheetDistributorEnum.ONLINE_PAYMENT_FLOW_LINK_TEXT.getAttr(), serialNo);
                data.put(PaymentSheetDistributorEnum.PAYER_ID.getAttr(), payerId);
                data.put(PaymentSheetDistributorEnum.PAYER.getAttr(), payerText);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("paymentSheetAnalyticalServiceImpl.beforeSave error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }



    public AddBatchDTO beforeSaveBatch(FormDataAddDTO formDataSaveDTO,  PaymentSheetTypeEnum paymentSheetTypeEnum, Long customerId, Boolean fromApproval) throws XbbException{
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formDataSaveDTO.getFormId(), formDataSaveDTO.getCorpid());
        if (Objects.isNull(paasFormExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
        JSONObject data = formDataSaveDTO.getDataList();
        SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CUSTOMER_ID.getAttr(), PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), PaymentSheetEnum.CUSTOMER_ID.getFieldType());
        SaveFormatHelp.formatLinkBusiness4Save(data, PaymentSheetEnum.CONTRACT.getAttr(), PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentSheetEnum.CONTRACT.getFieldType());
        Double contractAmount;
        SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = formDataSaveDTO.getSaasNeedRedundantAttrPoJo();
        if (Objects.nonNull(saasNeedRedundantAttrPoJo) && Objects.equals(saasNeedRedundantAttrPoJo.getParentBusinessType(), XbbRefTypeEnum.CONTRACT.getCode())) {
            contractAmount = formDataSaveDTO.getSaasNeedRedundantAttrPoJo().getParentAmount();
        } else {
            JSONArray idArray = data.getJSONArray(PaymentSheetEnum.CONTRACT.getAttr());
            Long dataId = 0L;
            if ( CollectionsUtil.isNotEmpty(idArray) ) {
                dataId = idArray.getLong(0);
            }
            PaasFormDataEntityExt contractEntityExt = contractModel.getByKey(dataId,formDataSaveDTO.getCorpid());
            if (Objects.isNull(contractEntityExt)) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }
            contractAmount = contractEntityExt.getData().getDouble(ContractEnum.AMOUNT.getAttr());
        }
        Double paymentSheetAmount = 0D;
        Double advancePaymentBalance = 0D;
        JSONArray paymentSheetArray = data.getJSONArray("addPaymentSheet");
        String xbbRefTypeName = XbbRefTypeEnum.PAYMENT_SHEET.getName();
        if ( Objects.equals(PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getCode()) ){
            paymentSheetArray = data.getJSONArray("addWriteOffPaymentSheet");
            xbbRefTypeName = XbbRefTypeEnum.WRITE_OFF_PREPAYMENT.getName();
        }

        List<AddMuchFieldPojo> addBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> delBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> updateBatchList = new ArrayList<>();
        List<ValidateDataDTO> validateDataDTOList = new ArrayList<>();
        FieldAttrEntity serialNoFieldAttr = explainMap.get(PaymentSheetEnum.SHEET_NO.getAttr());
        //下面是移除审批中已经删除的回款单
        fundHelp.handProcessShouldRemoveValue(formDataSaveDTO.getCorpid(), XbbRefTypeEnum.CONTRACT, XbbRefTypeEnum.PAYMENT_SHEET, paymentSheetArray);
        for (Object obj : paymentSheetArray){
            AddMuchFieldPojo addMuchFieldPojo = new AddMuchFieldPojo();
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            JSONObject json = (JSONObject) obj;
            Long dataId = json.getLong(StringConstant.DATA_ID);
            addMuchFieldPojo.setId(dataId);
            String serialNo = json.getString(FieldTypeEnum.SERIALNO.getAlias());
            if (Objects.nonNull(serialNoFieldAttr)) {
                if (Objects.equals(serialNoFieldAttr.getStrictController(), BasicConstant.ONE) && StringUtil.isEmpty(serialNo)) {
                    serialNo = serialNoHelp.getSerialNo(serialNo, formDataSaveDTO.getCorpid(), formDataSaveDTO.getFormId(),  serialNoFieldAttr);
                }
                addMuchFieldPojo.setSerialNo(serialNo);
            }
            if ( StringUtil.isNotEmpty(serialNo) && serialNo.length()>BasicConstant.SERIAL_LENGTH_NUMBER) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208059,String.format(PaymentErrorCodeEnum.API_ERROR_208059.getMsg(),xbbRefTypeName,BasicConstant.SERIAL_LENGTH_NUMBER));
            }
            JSONObject paymentSheetData = json.getJSONObject("data");
            if (Objects.isNull(paymentSheetData)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, SystemErrorCodeEnum.API_ERROR_100028.getMsg());
            }
            Integer alone = json.getInteger(BasicConstant.ALONE);
            boolean flag = Objects.isNull(dataId) && (Objects.isNull(alone) || Objects.equals(alone, SheetAloneEnum.NORMAL.getCode()));
            if (flag) {
                JSONArray belongIdArray = paymentSheetData.getJSONArray(PaymentSheetEnum.BELONG_ID.getAttr());
                if ( belongIdArray.size() > 1 ){
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), paymentSheetTypeEnum.getName());
                }
            }
            for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet()){
                SaasDataInitHelp.antDataSet(paymentSheetData,entry.getKey(),entry.getValue());
            }
            if ( Objects.equals(PaymentSheetTypeEnum.WRITE_OFF.getCode(), paymentSheetTypeEnum.getCode()) ){
                JSONObject jsonObject = FastJsonHelper.getJsonObjectFromFormData(paymentSheetData, PaymentSheetEnum.FUND_ACCOUNT.getAttr());
                if (Objects.nonNull(jsonObject)) {
                    paymentSheetData.put(PaymentSheetEnum.FUND_ACCOUNT.getAttr(),jsonObject.get(StringConstant.VALUE));
                }
                paymentSheetData.put(PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr(), getDoubleOrDefaultFromFormData(paymentSheetData, PaymentSheetEnum.AMOUNT.getAttr(), 0D));
            }
            if ( Objects.isNull(dataId)) {
                paymentSheetData.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), paymentSheetTypeEnum.getCode());
            }
            paymentSheetData.put(PaymentSheetEnum.CUSTOMER_ID.getAttr(),data.get(PaymentSheetEnum.CUSTOMER_ID.getAttr()));
            paymentSheetData.put(PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(),data.get(PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr()));
            paymentSheetData.put(PaymentSheetEnum.CONTRACT.getAttr(),data.get(PaymentSheetEnum.CONTRACT.getAttr()));
            paymentSheetData.put(PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(),data.get(PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr()));
            Integer operationFlag = json.getInteger(StringConstant.OPERATION_FLAG);
            addMuchFieldPojo.setData(paymentSheetData);
            if ( Objects.isNull(dataId) ) {
                operationFlag = null;
            }
            BeanUtil.copyProperties(formDataSaveDTO,validateDataDTO);
            validateDataDTO.setSerialNo(serialNo);
            validateDataDTO.setBusinessType(XbbRefTypeEnum.PAYMENT_SHEET.getCode());
            validateDataDTO.setData(addMuchFieldPojo.getData());
            validateDataDTO.setDataId(dataId);
            validateDataDTO.setFromApproval(fromApproval);
            if (Objects.equals(operationFlag, LinkAddOperationFlagEnum.DEL.getCode())){
                delBatchList.add(addMuchFieldPojo);
            }else {
                if (Objects.equals(operationFlag,LinkAddOperationFlagEnum.EDIT.getCode())){
                    updateBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    validateTeam(paymentSheetData, validateDataDTO, addMuchFieldPojo, formDataSaveDTO.getDistributorMark());
                }else if (Objects.isNull(dataId)){
                    //为了防止进入审批，前置传入
                    addMuchFieldPojo.setAlone(SheetAloneEnum.NORMAL.getCode());
                    addMuchFieldPojo.setUuid(UUID.randomUUID().toString());
                    addBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    if ( Objects.equals(PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getCode()) ) {
                        advancePaymentBalance = Arith.add(advancePaymentBalance, getDoubleOrDefaultFromFormData(paymentSheetData, PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D));
                    }
                    validateTeam(paymentSheetData, validateDataDTO, addMuchFieldPojo, formDataSaveDTO.getDistributorMark());
                }
                if ( Objects.equals(PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getCode())  ){
                    paymentSheetAmount = Arith.add(paymentSheetAmount, getDoubleOrDefaultFromFormData(paymentSheetData, PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D));
                } else {
                    paymentSheetAmount = Arith.add(paymentSheetAmount, getDoubleOrDefaultFromFormData(paymentSheetData, PaymentSheetEnum.AMOUNT.getAttr(), 0D));
                }
            }
            //校验团队负责人之后需要重新变成原来入参的样子，因为这边回款单校验也会走一次这个ProSaveHelp.analyticalData方法
            JSONArray originalOwnerArray = paymentSheetData.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
            JSONArray originalCouserArray = paymentSheetData.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
            validateDataDTO.setExplainMap(explainMap);
            // 标签设置
            SaveFormatHelp.dealLabelData(validateDataDTO.getData(), validateDataDTO.getExplainMap());
            ProSaveHelp.analyticalData(validateDataDTO);
            formDataValidateDataHelp.validateData(validateDataDTO);
            addMuchFieldPojo.setDepartmentId(validateDataDTO.getDepartmentId());
            paymentSheetData.put(FieldTypeEnum.DEPARTMENTID.getAlias(), validateDataDTO.getDepartmentId());
            paymentSheetData.put(FieldTypeEnum.OWNERID.getAlias(), originalOwnerArray);
            paymentSheetData.put(FieldTypeEnum.COUSERID.getAlias(), originalCouserArray);
        }
        if ( Objects.equals(PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode(), paymentSheetTypeEnum.getCode()) && advancePaymentBalance > 0 ) {
            PaymentBalanceEntity paymentBalanceEntity = paymentBalanceModel.getByCustomerId(customerId, formDataSaveDTO.getCorpid());
            if ( paymentBalanceEntity == null || paymentBalanceEntity.getAdvancePaymentBalance() < advancePaymentBalance ) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208036, PaymentErrorCodeEnum.API_ERROR_208036.getMsg());
            }
        }
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(paymentSheetAmount, contractAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208046, PaymentErrorCodeEnum.API_ERROR_208046.getMsg(), paymentSheetTypeEnum.getName());
        }
        AddBatchDTO addBatchDTO = new AddBatchDTO();
        BeanUtil.copyProperties(formDataSaveDTO,addBatchDTO);
        addBatchDTO.setAddBatchList(addBatchList);
        FieldAttrEntity serialField = explainMap.getOrDefault(PaymentSheetEnum.SHEET_NO.getAttr(), new FieldAttrEntity());
        if (Objects.equals(serialField.getNoRepeat(), 1)) {
            Set<String> addSerialNoSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            addBatchList.forEach(addBatch-> addSerialNoSet.add(addBatch.getSerialNo()));
            if (!Objects.equals(addSerialNoSet.size(), addBatchList.size())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_REPEAT, serialField.getAttrName());
            }
        }
        Integer total = addBatchList.size() + updateBatchList.size() - delBatchList.size();
        if ( Objects.equals(paymentSheetTypeEnum.getCode(), PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode()) ){
            if ( /*formDataSaveDTO.getIsNew() &&*/ total > StringConstant.MAX_WRITE_OFF_PREPAYMENT_COUNT ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.OVER_STEP_MAX_WRITE_OFF_PREPAYMENT_COUNT, StringConstant.MAX_WRITE_OFF_PREPAYMENT_COUNT);
            }
        } else if (Objects.equals(paymentSheetTypeEnum.getCode(), PaymentSheetTypeEnum.WRITE_OFF.getCode())){
            if ( /*formDataSaveDTO.getIsNew() &&*/ total > StringConstant.MAX_PAYMENT_SHEET_COUNT ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.OVER_STEP_MAX_PAYMENT_SHEET_COUNT, StringConstant.MAX_PAYMENT_SHEET_COUNT);
            }
        }
        addBatchDTO.setAmount(paymentSheetAmount);
        addBatchDTO.setUpdateBatchList(updateBatchList);
        addBatchDTO.setDelBatchList(delBatchList);
        addBatchDTO.setValidateDataDTOList(validateDataDTOList);
        return addBatchDTO;
    }

    /**
     * 校验团队并且往参数中封装团队信息
     *
     * @param json
     * @param validateDataDTO
     * @param addMuchFieldPojo
     * @param distributorMark
     */
    private void validateTeam(JSONObject json, ValidateDataDTO validateDataDTO, AddMuchFieldPojo addMuchFieldPojo, Integer distributorMark) throws XbbException {
        if (Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode())) {
            return;
        }
        JSONArray teamMainPojoArray = json.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
        JSONArray teamCoPojoArray = json.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
        //因为合同批量新建回款单的时候，validateDataDTO最外层也有合同的负责任人、协同人，所以需要把最外层的先移除掉
        validateDataDTO.setOwnerIds(null);
        validateDataDTO.setCoUserId(null);
        if (Objects.nonNull(teamMainPojoArray) && teamMainPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> ownerIds = teamMainPojoArray.toJavaList(ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setOwnerIds(ownerIds);
        }
        if (Objects.nonNull(teamCoPojoArray) && teamCoPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> coUserIds = teamCoPojoArray.toJavaList(ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setCoUserId(coUserIds);
        }
        try{
            teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
            TeamAfterVerifyDTO teamAfterVerifyDTO = validateDataDTO.getSaasNeedRedundantAttrPoJo().getTeamAfterVerifyDTO();
            addMuchFieldPojo.setTeamAfterVerifyDTO(teamAfterVerifyDTO);
        }catch (XbbException e){
            throw new XbbException(e.getCode(), teamUserHelp.formatErrorMessage(e.getCode(), e.getMsg(), XbbRefTypeEnum.PAYMENT_SHEET));
        }

    }

    /**
     * 已核销、预收款核销回款单条件封装
     *
     * @param validateDataDTO
     * @param sheetTypeEnum
     * @throws XbbException
     */
    public void writeOffBeforeSave(ValidateDataDTO validateDataDTO, SheetTypeEnum sheetTypeEnum) throws XbbException{
        /*
         已核销回款：回款金额、核销金额同时置值
         */
        JSONObject dataList = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        String userId = validateDataDTO.getUserId();
        if (Objects.nonNull(validateDataDTO.getProcessCreatorId())) {
            userId = validateDataDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = validateDataDTO.getAmountDetail();
        //TODO 金额校验，后续修改成根据每条明细判断，暂时未用到
        double allAmount = 0D;
        //应收款和合同对应的回款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //回款单的实收回款金额
        Double sheetAmount;
        boolean writeOffPrepaymentFlag = SheetTypeEnum.onlyWriteOffAmount(sheetTypeEnum.getCode());
        if (writeOffPrepaymentFlag) {
            //预收款核销，是用的核销金额
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D);
            //检查预收款核销金额是否小于客户余额
            saasPaymentSheetHelper.checkCustomerBalance(dataList, corpid, sheetAmount);
        } else {
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaymentSheetEnum.AMOUNT.getAttr(), 0D);
        }
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(XbbRefTypeEnum.PAYMENT_SHEET);
        /*
          经销商类型回款单，需要做如下事情：
          （1）（经销商端判断，此处不判断）上传凭证：线下支付则必填
          （2）支付方式，厂商端操作需后端自动赋值 - handleAmountDetail方法内处理
                代客操作：已核销，预收款
                预收款账户：预收款核销，红冲预收款核销（退到余额）
                线下打款：红冲预收款核销（原Pro的），红冲预收款余额
                另外，红冲已核销与原单一致（关联新建时处理好）
          （3）上游订货单（合同）付款状态更新
         */
        Integer distributorMark = validateDataDTO.getDistributorMark();
        validateDataDTO.setDistributorMark(distributorMark);
        //校验金额明细
        saasSaveHelper.checkAmountDetail(validateDataDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Double sumAmount = getSumAmount(validateDataDTO, contractIds, paymentIds, null);
        LOGGER.info("添加回款单时，合同的未收金额和回款金额日志打印,合同未收金额："+ sumAmount +" , 回款金额 ： "+ sheetAmount);
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, I18nMessageUtil.getMessage(ErrorMessageConstant.BEYOND_AMOUNT));
        }
        //判断已收金额是否已经超过应收款内的未收金额
        saasPaymentHelper.checkPayment(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //判断已收金额是否已经超过合同内的未收金额
        PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(sheetTypeEnum.getCode());
        contractHelp.checkContract(distributorMark, paymentSheetTypeEnum, corpid, contractIdToAmount, contractIds);
        PaymentSheetEntityExt paymentSheetEntityExt = new PaymentSheetEntityExt();
        BeanUtil.copyProperties(validateDataDTO, paymentSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, paymentSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
    }


    /**
     * 得到回款单可回款（可红冲、可坏账）金额
     * 回款、坏账：获取合同/应收款的未收
     * 红冲：获取（红冲回款单关联的合同/应收款的）已收
     * @param validateDataDTO 回款单保存dto
     * @param contractIds 创建的回款单关联的合同id集合
     * @param paymentIds 创建的回款单关联的回款id集合
     * @param linkPreId 关联原始回款单id
     * @return java.lang.Double
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private Double getSumAmount(ValidateDataDTO validateDataDTO, Set<Long> contractIds, Set<Long> paymentIds, Long linkPreId) throws XbbException {
        SheetAmountDetailGetDTO sheetAmountDetailGetDTO = new SheetAmountDetailGetDTO();
        BeanUtil.copyProperties(validateDataDTO, sheetAmountDetailGetDTO);
        sheetAmountDetailGetDTO.setDataIdList(new ArrayList<>(contractIds));
        //空的数组也作为筛选条件
        sheetAmountDetailGetDTO.setEmptyFilterFlag(true);
        sheetAmountDetailGetDTO.setPaymentIdList(new ArrayList<>(paymentIds));
        sheetAmountDetailGetDTO.setLinkPreId(linkPreId);
        SheetAmountDetailGetVO sheetAmountDetailGetVO = saasPaymentHelper.paymentAmountDetailGet(true, sheetAmountDetailGetDTO);
        return sheetAmountDetailGetVO.getSumAmount();
    }
}
